package cli

import (
	"strings"
	"fmt"
	"regexp"
	"encoding/json"

	"gitee.com/wint/tge/session"
)

type CmdManager struct {
	cmds	map[string]*Cmd
	cmdList	[]*Cmd
	re 		*regexp.Regexp
}

func NewCmdManager() *CmdManager {
	m := &CmdManager{}
	m.cmds = make(map[string]*Cmd)
	m.re = regexp.MustCompile("\\s+")
	m.AddHelpCmd()
	return m
}

func (m *CmdManager) AddCmd(c *Cmd) {
	m.cmds[c.Name] = c
	m.cmdList = append(m.cmdList, c)
}

// 解析命令字符串并执行，命令字符串可以是 cmd arg ... 这种格式，也可以是 json 格式
// json 格式下　cmd 为保留关键字，用于指定所要执行的命令
func (m *CmdManager) Execute(s string, ses *session.Session) {
	defer func() {
		if err := recover(); err != nil {
			fmt.Println(err)
		}
	} ()

	s1 := strings.TrimSpace(s)
	if "" != s1 {
		if strings.Contains(s1, "{") {
			// json 格式
			var v map[string]interface{}
			if nil == json.Unmarshal([]byte(s1), &v) {
				if cmd, ok := v["cmd"]; ok {
					if cmdName, ok1 := cmd.(string); ok1 {
						if c, ok := m.cmds[cmdName]; ok {
							c.ExecuteJson(v, ses)
						}
					} else {
						m.Println(ses, "cmd isn't str type " + s)
					}
				} else {
					m.Println(ses, "cmd with json str " + s)
				}
				return
			}
		}
		sList := m.re.Split(s1, -1)
		if len(sList) > 0 {
			if c, ok := m.cmds[sList[0]]; ok {
				c.Execute(sList[1:], ses)
			} else {
				m.Println(ses, "no cmd name " + sList[0] + " with cmd " + s)
			}
		}
	}
}

func (m *CmdManager) Println(ses *session.Session, s string) {
	if nil != ses {
		ses.Send(s)
	} else {
		fmt.Println(s)
	}
}

func (m *CmdManager) PrintUsage(ses *session.Session) {
	for _, v := range m.cmdList {
		v.PrintSimpleUsage(ses)
	}
}

func (m *CmdManager) CheckCmds() {
	for _, v := range m.cmdList {
		v.IsValid(nil)
	}
}

func (m *CmdManager) AddHelpCmd() {
	c := &Cmd{}
	c.Name = "help"
	c.Usage = "show all cmds"
	c.AddArgParam("name", "", "help command name", false)
	c.SetHandler(m.onHelp)
	m.AddCmd(c)
}

func (m *CmdManager) onHelp(ses *session.Session, name string) {
	if "" != name {
		if c, ok := m.cmds[name]; ok {
			c.PrintUsage(ses)
		} else {
			if nil != ses {
				ses.Send("no cmd name " + name)
			} else {
				fmt.Println("no cmd name " + name)
			}
		}
	} else {
		m.PrintUsage(ses)
	}
}

var mgr = NewCmdManager()

func AddCmd(c *Cmd) {
	mgr.AddCmd(c)
}

func Execute(s string, ses *session.Session) {
	mgr.Execute(s, ses)
}

func Println(ses *session.Session, s string) {
	mgr.Println(ses, s)
}

func PrintlnJson(ses *session.Session, i interface{}) {
	if b, err := json.Marshal(i); nil == err {
		mgr.Println(ses, string(b))
	}
}

func PrintUsage(ses *session.Session) {
	mgr.PrintUsage(ses)
}


func CheckCmds() {
	mgr.CheckCmds()
}